package controllers;

import java.util.ArrayList;
import java.util.List;

import controllers.Relations;

import play.data.validation.Required;
import play.mvc.Controller;

import models.Entities;
import models.Organization;
import models.Relation;
import models.RelationNames;
import models.Tag;
import models.Topic;
import models.User;
import models.Permission;

public class Relations extends Controller {
	/**
	 * @author Menna Magdy save in it the organizationId that we stand on
	 */
	public static long organizationId;
	/**
	 * @author Menna Magdy save in it the relationId that user need to rename it
	 */
	public static long relationId;
	/**
	 * @author Menna Magdy save in it the relationNameId that user need to
	 *         delete it
	 */
	public static long relationNameId;
	/**
	 * @author Menna Magdy save in it the user's permission type
	 */
	public static String permissionType;

	/**
	 * renders a page with all entities in organization that is unlocked and
	 * show all relation names created in this organization so that the user can
	 * create new relation among entities
	 * 
	 * @author Menna Magdy
	 */
	public static void relateEntity() {
		try{
		Organization organization = Organization.findById(organizationId);
		List<Entities> entities = organization.allEntities;
		List<Entities> entity = new ArrayList<Entities>();
		for (int i = 0; i < entities.size(); i++) {
			if (entities.get(i).isLocked == false)
				entity.add(entities.get(i));
		}
		String userType = permissionType;
		List<RelationNames> task = organization.relationNameList;
		render(entity, task, userType);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * renders a page with all topic in organization that is unlocked and show
	 * all relation names created in this organization so that the user can
	 * create new relation among topics
	 * 
	 * @author Menna Magdy
	 */
	public static void relateTopic() {
		try{
		Organization organization = Organization.findById(organizationId);
		List<Entities> entity = organization.allEntities;
		List<Topic> topic = new ArrayList<Topic>();
		for (int i = 0; i < entity.size(); i++) {
			for (int j = 0; j < entity.get(i).topics.size(); j++) {
				if (entity.get(i).topics.get(j).isLocked == false)
					topic.add(entity.get(i).topics.get(j));
			}
		}
		String userType = permissionType;
		List<RelationNames> task = organization.relationNameList;
		render(entity, topic, task, userType);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * renders a page with all tags in organization and show all relation names
	 * created in this organization so that the user can create new relation
	 * among tags
	 * 
	 * @author Menna Magdy
	 */
	public static void relateTag() {
		try{
		Organization organization = Organization.findById(organizationId);
		List<Tag> tag = organization.tags;
		List<RelationNames> task = organization.relationNameList;
		String userType = permissionType;
		render(task, tag, userType);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * checks if the new relation is valid through calling
	 * checkEntitiesRelation, then if its valid addEntitiesRelation method in
	 * the organization class will be called to add the new relation of entities
	 * 
	 * @params relationName new relationName
	 * @params source source of relation
	 * @params destination destination of relation
	 * @author Menna Magdy
	 * 
	 */
	public static void addEntitiesRelation(@Required String relationName,
			@Required String source, @Required String destination) {
		try{
		if (validation.hasErrors()) {
			flash.error("Please select values from all boxes!");
			relateEntity();
		}

		Organization organization = Organization.findById(organizationId);
		String userIdString = session.get("userId");
		if (userIdString == null) {
			Home.home(null, null, "Please Login");
		}
		Long userId = Long.parseLong(userIdString);
		User author = User.findById(userId);

		String action = organization.checkEntitiesRelation(author, source,
				destination, relationName);
		if (action != "go") {
			flash.error(action);
			relateEntity();
		}
		Relation relation = null;
		if (action == "go") {
			relation = organization.addEntitiesRelation(author, relationName,
					source, destination);
		}
		List<Relation> view = organization.relationList;
		String message = "Your new relation has been added Successfully!!";
		showRelation(message);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * checks if the new relation is valid through calling checkTopicRelation,
	 * then if its valid addTopicRelation method in the organization Class will
	 * be called to add the new relation of topics
	 * 
	 * @params relationName new relationName
	 * @params source source of relation
	 * @params destination destination of relation
	 * @author Menna Magdy
	 * 
	 */
	public static void addTopicRelation(@Required String relationName,
			@Required String source, @Required String destination) {
		try{
		Organization organization = Organization.findById(organizationId);
		String userIdString = session.get("userId");
		if (userIdString == null) {
			Home.home(null, null, "Please Login");
		}
		Long userId = Long.parseLong(userIdString);
		User author = User.findById(userId);

		if (validation.hasErrors()) {
			flash.error("Please select values from all boxes!");
			relateTopic();
		}
		Relation relation = null;
		String action = organization.checkTopicRelation(author, source,
				destination, relationName);
		if (action != "go") {
			flash.error(action);
			relateTopic();
		}
		if (action == "go")
			relation = organization.addTopicRelation(author, relationName,
					source, destination);
		List<Relation> view = organization.relationList;
		String message = "Your new relation has been added Successfully!!";
		showRelation(message);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * checks if the new relation is valid through calling checkTagRelation,
	 * then if its valid addTagsRelation method in the organization class will
	 * be called to add the new relation of tags
	 * 
	 * @params relationName new relationName
	 * @params source source of relation
	 * @params destination destination of relation
	 * @author Menna Magdy
	 * 
	 */
	public static void addTagRelation(@Required String relationName,
			@Required String source, @Required String destination) {
	   try{
		Organization organization = Organization.findById(organizationId);
		String userIdString = session.get("userId");
		if (userIdString == null) {
			Home.home(null, null, "Please Login");
		}
		Long userId = Long.parseLong(userIdString);
		User author = User.findById(userId);

		if (validation.hasErrors()) {
			flash.error("Please select values from all boxes!");
			relateTag();
		}
		Relation relation = null;
		String action = organization.checkTagRelation(author, source,
				destination, relationName);
		if (action != "go") {
			flash.error(action);
			relateTag();
		}
		if (action == "go")
			relation = organization.addTagRelation(author, relationName,
					source, destination);
		List<Relation> view = organization.relationList;
		String message = "Your new relation name has been added Successfully!!";
		showRelation(message);
	   }
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * renders a page with all relations created in the organization
	 * 
	 * @param message
	 *            contains the confirmation message after any changes in the
	 *            relations or new relation created
	 * @author Menna Magdy
	 */
	public static void showRelation(String message) {
       try{
		Organization organization = Organization.findById(organizationId);
		List<Relation> view = organization.relationList;
		String userType = permissionType;
		render(view, message, userType);
       }catch(NullPointerException error){
			Requests.contentNotFound();
		}

	}

	/**
	 * renders a pages with the relation source and destination with all
	 * relation names available in the organization to choose one from them for
	 * renaming the relation
	 * 
	 * @params idForRelation the relation id that the user wants to rename it
	 * @author Menna Magdy
	 * 
	 */
	public static void renameRelation(Long idForRelation) {
        try{
		relationId = idForRelation;
		Relation relation = Relation.findById(idForRelation);
		Organization organization = Organization.findById(organizationId);
		List<RelationNames> task = organization.relationNameList;
		String userType = permissionType;
		render(relation, task, userType);
        }
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * checks if the relation with the new name is valid through calling
	 * checkTagRelation,checkEntitiesRelation & checkTopicRelation, then if its
	 * the relation will be updated with the new name requested
	 * 
	 * @params newRelationName the new relationName choosed
	 * @author Menna Magdy
	 * 
	 */
	public static void renameDone(@Required String newRelationName) {
        try{
		Long relationId2 = relationId;
		String name = newRelationName;
		Organization organization = Organization.findById(organizationId);
		String userIdString = session.get("userId");
		if (userIdString == null) {
			Home.home(null, null, "Please Login");
		}
		Long userId = Long.parseLong(userIdString);
		User author = User.findById(userId);
		Relation relation = Relation.findById(relationId2);

		if (newRelationName.equalsIgnoreCase(relation.relationName)) {
			flash.error("*Same relation name!! Please select the new relation name!!");
			renameRelation(relation.id);
		}
		String action = " ";
		if (relation.type.equalsIgnoreCase("entity"))
			action = organization.checkEntitiesRelation(author,
					relation.source, relation.destination, newRelationName);
		if (relation.type.equalsIgnoreCase("topic"))
			action = organization.checkTopicRelation(author, relation.source,
					relation.destination, newRelationName);
		if (relation.type.equalsIgnoreCase("tag")) {
			action = organization.checkTagRelation(author, relation.source,
					relation.destination, newRelationName);
		}

		if (action == "go") {
			relation.relationName = newRelationName;
			relation.save();
		}
		if (action != "go") {
			flash.error(action);
			renameRelation(relation.id);
		}
		String message = "The relation has been renamed successfully!!!!";
		showRelation(message);
        }
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
    	}

	/**
	 * shows all relation names that have been created in the organization
	 * 
	 * @param message
	 *            contains the confirmation message after any changes in the
	 *            relations or new relation created
	 * @author Menna Magdy
	 */
	public static void showNames(String message) {
		try{
		Organization organization = Organization.findById(organizationId);
		List<RelationNames> view = organization.relationNameList;
		String userType = permissionType;
		render(view, message, userType);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * takes the relation name id that needed to be deleted then searches for
	 * any relation that uses this relation name whether a tag,topic or entity
	 * relations, and delete this relation, at the end delete this relation name
	 * and renders a page that shows all relation names available
	 * 
	 * @params newNameId relation name id
	 * @author Menna Magdy
	 * 
	 */
	public static void deleteName(Long deletedRelationNameId) {
		try{
		relationNameId = deletedRelationNameId;
		Organization organization = Organization.findById(organizationId);
		RelationNames oldRelationName = RelationNames.findById(relationNameId);

		for (int j = organization.relationList.size() - 1; j >= 0; j--) {
			if (oldRelationName.relationName
					.equalsIgnoreCase(organization.relationList.get(j).relationName)
					&& organization.relationList.get(j).type
							.equalsIgnoreCase("tag"))
				organization.relationList.get(j).unassignTagRelation();
		}
		for (int j = organization.relationList.size() - 1; j >= 0; j--) {
			if (oldRelationName.relationName
					.equalsIgnoreCase(organization.relationList.get(j).relationName)
					&& organization.relationList.get(j).type
							.equalsIgnoreCase("entity"))
				organization.relationList.get(j).unassignEntityRelation();
		}
		for (int j = organization.relationList.size() - 1; j >= 0; j--) {
			if (oldRelationName.relationName
					.equalsIgnoreCase(organization.relationList.get(j).relationName)
					&& organization.relationList.get(j).type
							.equalsIgnoreCase("topic"))
				organization.relationList.get(j).unassignTopicRelation();
		}
		organization.relationNameList.remove(oldRelationName);
		oldRelationName.organization = null;
		oldRelationName.save();
		organization.save();
		oldRelationName.delete();
		String message = "Your new relation name has been deleted Successfully!!";
		showNames(message);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * renders a page with all options of Relations "create,request,etc."
	 * 
	 * @param id
	 *            the id of the organization
	 * 
	 * @author Menna Magdy
	 */
	public static void relatePage(Long id) {
		try{
		String userIdString = session.get("userId");
		if (userIdString == null) {
			Home.home(null, null, "Please Login");
		}
		Long userId = Long.parseLong(userIdString);
		User author = User.findById(userId);
		organizationId = id;
		Organization organization = Organization.findById(organizationId);

		String userType = "";
		Permission permission = Permission.find("user=? AND aUserType=?",
				author, "systemAdmin").first();
		if (permission != null) {
			userType = permission.aUserType;
		} else {
			if (author.equals(organization.lead))
				userType = "organizationLead";
			else {
				permission = Permission.find(
						"user=? AND organization=? AND aUserType=?", author,
						organization, "organizer").first();
				if (permission != null) {
					userType = permission.aUserType;
				} else {
					permission = User.userPermissionInOrganization(userId,
							organizationId);
					userType = permission.aUserType;
				}
			}
		}
		permissionType = userType;
		render(userType);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * renders a page with two options related to the requesting of any relation
	 * 
	 * @author Menna Magdy
	 */
	public static void requestPage(String message) {
		try{
		Long idForOrganization = organizationId;
		String userIdString= session.get("userId");
		if (userIdString == null) {
			Home.home(null, null, "Please Login");
		}
		Long userId = Long.parseLong(userIdString);
		User author = User.findById(userId);
		Organization organization = Organization.findById(organizationId);
		String userType = permissionType;
		render(idForOrganization, userType, message);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * renders a page with four buttons contains the different types of
	 * relation's creation
	 * 
	 * @author Menna Magdy
	 */
	public static void createRelationsPage() {
		try{
		Long idForOrganization = organizationId;
		Organization organization = Organization.findById(organizationId);
		String userType = permissionType;
		render(idForOrganization, userType);
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

	/**
	 * search for the relation in the system by the relation id then calls the
	 * method checkRelationType() in the relation model, this method checks the
	 * type and unassign the required relation
	 * 
	 * @param relationId
	 *            the relation that should be unassigend
	 * @author Mai Abu-El Seoud
	 */
	public static void unassignRelation(Long relationId) {
		try{
		Relation relation = Relation.findById(relationId);
		relation.checkRelationType();
		showRelation("The relation has been deleted successfully!!");
		}
		catch(NullPointerException error){
			Requests.contentNotFound();
		}
	}

}